package com.cxx.autoconfigure.interceptor;

import com.cxx.autoconfigure.constant.Constants;
import com.cxx.autoconfigure.util.WebUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 审计拦截器 可以实现请求日志打印等功能
 * <p>
 * HandlerInterceptor 拦截器执行顺序：
 * 1. preHandle()：请求处理前 按注册顺序依次执行。
 * 2. Controller：请求处理 请求到达Controller并被处理。
 * 3. postHandle()：请求处理后，视图渲染前 按注册顺序逆序执行。
 * 4. afterCompletion()：视图渲染后 按注册顺序逆序执行。
 */
public class AuditInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(AuditInterceptor.class);

    private final String basePackage;

    public AuditInterceptor(String basePackage) {
        this.basePackage = basePackage;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 如果是Http请求
        if (handler instanceof HandlerMethod hd) {
            request.setAttribute(Constants.AUDIT_TIME_FLAG, System.currentTimeMillis());
            // 判断该请求是否需要审计
            if (WebUtils.checkIsAuditPackages(hd.getBeanType().getPackage(), basePackage)) {
                handleAuditPackageRequest(request);
            }
        }

        // true表示继续处理请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 这里我们不需要处理时间计算，所有的计算在 afterCompletion 中完成
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 获取开始时间
        Long startTime = (Long) request.getAttribute(Constants.AUDIT_TIME_FLAG);
        if (startTime != null) {
            long duration = System.currentTimeMillis() - startTime;
            logger.info("<AuditSummary> Request URL {} | Time Taken {} ms", request.getRequestURI(), duration);
        }
    }

    /**
     * 处理审计包请求
     * @param request 请求
     */
    private void handleAuditPackageRequest(HttpServletRequest request) {
        if (StringUtils.isEmpty(request.getQueryString())) {
            logger.info("<AuditSummary> {} {}", request.getMethod(), request.getRequestURI());
        } else {
            logger.info("<AuditSummary> {} {}?{}", request.getMethod(), request.getRequestURI(), WebUtils.format2UTF8(request.getQueryString()));
        }
    }
}
